﻿using FastCode.Helper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace FastCode.Filters
{
    public class TokenValidationFilter(IConfiguration configuration) : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {

            var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
            if (actionDescriptor != null)
            {
                var isAnonymous = actionDescriptor.MethodInfo.GetCustomAttributes(inherit: true)
                    .Any(a => a.GetType() == typeof(AllowAnonymousAttribute));
                if (isAnonymous)
                {
                    await next();
                    return;
                }
            }

            string? authHeader = context.HttpContext.Request.Headers["Authorization"];

            if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer "))
            {
                context.Result = new UnauthorizedResult();
                return;
            }

         

            var token = authHeader.Substring("Bearer ".Length).Trim();

            var claimsPrincipal = IsValidToken(token);
            if (claimsPrincipal == null)
            {
                context.Result = new UnauthorizedResult();
                return;
            }

            // Resolve the IUserService from the service provider
            var userService = context.HttpContext.RequestServices.GetRequiredService<UserService>();
            // Get the current user
            var user = await userService.GetCurrentUserAsync(claimsPrincipal.FindFirstValue(ClaimTypes.NameIdentifier));
            if (user == null)
            {
                context.Result = new UnauthorizedResult();
                return;
            }
            //var user = await _userManager.FindByIdAsync(userId);
            var userPwdUpdateStr = user.PasswordLastUpdated == null ? string.Empty : user.PasswordLastUpdated.Value.ToString();
            if (userPwdUpdateStr != claimsPrincipal.FindFirst(ConstData.PasswordLastUpdated)?.Value)
            {
                //throw new SecurityTokenExpiredException("Token has expired due to password change.");
                context.Result = new UnauthorizedResult();
                return;
            }

            context.HttpContext.User = claimsPrincipal;
            await next();
        }


        private ClaimsPrincipal? IsValidToken(string token)
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var validationParameters = GetValidationParameters();

            try
            {
                var claimsPrincipal = tokenHandler.ValidateToken(token, validationParameters, out var rawValidatedToken);

                return claimsPrincipal;
            }
            catch
            {
                return null;
            }

        }

        private TokenValidationParameters GetValidationParameters()
        {
            return new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,

                ValidIssuer = configuration["Jwt:Issuer"],
                ValidAudience = configuration["Jwt:Issuer"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:Secret"]??string.Empty))
            };
        }
    }
}
